from __future__ import absolute_import, unicode_literals
import json
import requests
import hashlib
from core.tools.custom_requests import SSLRequests
from hashlib import sha256
import hmac
import base64
import rsa
from core.tools.func_utils import FuncUtils
from core.tools.encryption import hashlib_md5
from urllib import parse
from finance_c2c.local_settings import mechCertKey, bankCertKey

funcUtils = FuncUtils()


class BaseClient(SSLRequests):
    @property
    def get_private_key(self):
        private_key = getattr(self, "private_key", None)
        if private_key:
            return private_key
        else:
            raise Exception("没有配置应用私钥")

    @property
    def get_public_key(self):
        public_key = getattr(self, "public_key", None)
        if public_key:
            return public_key
        else:
            raise Exception("没有配置应用公钥")

    def get_msg_header(self):
        sn = funcUtils.unique_value
        params = {
            "drctn": "I",  # （'I'-请求报文；'O'-响应报文）
            "sn": sn,
            "source": "WAP",
            "mechCertKey": mechCertKey,  # 签名证书序列号-商户私钥
            "bankCertKey": bankCertKey,  # 签名证书序列号-银行公钥
            "ver": "1.0",
            "ip": "127.0.0.1",
        }
        return params

    # 签名通过私钥
    # 第二步：进行签名处理 对stringD使用SHA1withRSA算法进行签名，生成签名结果stringE。
    def sign_with_rsa(self, content):
        signature = rsa.sign(content, rsa.PrivateKey.load_pkcs1(self.get_private_key, format='PEM'), 'SHA-1')
        # 第三步 BASE64编码处理 对stringE进行Base64编码生成stringF，stringF作为最终签名值放入请求报文中的msgSignature域中。
        sign = base64.b64encode(signature).decode('utf-8')  # 第三步：将待签名内容签名后进行Base64编码作为签名值。
        return sign

    def get_sign(self, all_params):
        sign_content_md5_upper = self.get_sign_base64_data(all_params)
        sign = self.sign_with_rsa(sign_content_md5_upper)  # 通过私钥签名
        return sign

    # 第一步：拼接待签数据字符串
    def get_sign_base64_data(self, all_params):
        # 1、将请求报文msgBody中的所有字段提取出来为集合M；
        # 2、将集合M内非空参数值的参数按照参数名ASCII码从小到大进行排序（字典序）（注：去除参数中的所有空格）
        # 3、对参数值（非空）进行encodingURIComponent编码；
        # 4、使用URL键值对的格式（即key1=value1&key2=value2…）将参数名与参数值拼接成字符串stringA；
        sign_content = self.get_sign_content(all_params)
        # 5、对stringA进行MD5处理生成stringB，将stringB转换成全大写字符串stringC；
        sign_md5_upper = hashlib_md5(sign_content).upper()
        # 6、将stringC进行base64编码后作为待签名字符串stringD。
        sign_content_md5_upper = base64.b64encode(sign_md5_upper.encode("utf-8"))
        return sign_content_md5_upper

    def get_sign_md5_upper(self, all_params):
        sign_content = self.get_sign_content(all_params)
        sign_md5 = hashlib_md5(sign_content)
        sign_md5_upper = sign_md5.upper()
        return sign_md5_upper

    @classmethod
    def get_sign_content(cls, all_params):
        d = dict()
        for k, v in all_params.items():
            value = v
            if not isinstance(value, str):
                value = json.dumps(value, ensure_ascii=False)
            value = value.replace(" ", "")
            if value:
                d[k] = value
        s = sorted(d.items(), key=lambda kv: (kv[0], kv[1]))
        sign_content = parse.urlencode(s)
        return sign_content

    # 用对方公钥验签
    def verify_with_rsa(self, message, sign):
        from Crypto.Hash import SHA
        from Crypto.Signature import PKCS1_v1_5
        from Crypto.PublicKey import RSA
        sign_content_md5_upper = self.get_sign_base64_data(message)
        sign = base64.b64decode(sign)
        publickey = RSA.importKey(self.get_public_key)
        verifier = PKCS1_v1_5.new(publickey)
        return bool(verifier.verify(SHA.new(sign_content_md5_upper), sign))
